package uk.co.q3c.deplan.client.domain.util;

import java.io.Serializable;
import java.util.Date;
import java.util.LinkedList;
import java.util.logging.Logger;

import javax.persistence.Id;

import uk.co.q3c.deplan.client.util.Q3DateUtil;

import com.googlecode.objectify.annotation.Cached;
import com.googlecode.objectify.annotation.Unindexed;

@Unindexed
@Cached(expirationSeconds = 600)
public abstract class DailyProfile_LinkedList<E extends DateProfileEntry> implements Serializable {
	protected static final Logger logger = Logger.getLogger(DailyProfile_LinkedList.class.getName());
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	@Id
	private Long keyId;

	protected DailyProfile_LinkedList() {
		super();
	}

	/**
	 * Duplicate and null rejected, but no exception. It is expected that entries would generally be added at the end of the list, so this
	 * method is biased towards that situation for performance
	 * 
	 * @param entry
	 */
	public void addEntry(E newEntry) {
		if (newEntry == null) {
			logger.fine("DailyProfile_LinkedList rejects null entry of ");
			return;
		}
		if (profile().size() == 0) {
			profile().addLast(newEntry);
			return;
		}
		if (newEntry.compareTo(profile().getLast()) > 0) {
			profile().addLast(newEntry);
			return;
		}
		// not available in GWT
		// Iterator<E> iter = profile().descendingIterator();
		boolean done = false;
		for (int i = profile().size() - 1; i > -1; i--) {
			E cursorEntry = profile().get(i);
			int comparison = newEntry.compareTo(cursorEntry);
			if (comparison > 0) {
				profile().add(i + 1, newEntry);
				done = true;
				break;
			} else {
				if (comparison == 0) {
					logger.fine("DailyProfile_LinkedList rejects duplicate entry of " + newEntry.getDateKey());
					done = true;
					break;
				}
			}

		}
		if (!done) {
			profile().addFirst(newEntry);
		}
	}

	public E getEntry(String dateKey) {
		return find(dateKey);
	}

	/**
	 * This could be made quicker by using a split search
	 * 
	 * @param dateKey
	 * @return
	 */
	private E find(String dateKey) {
		E result = null;
		for (E entry : profile()) {
			if (entry.getDateKey()
					.equals(dateKey)) {
				result = entry;
				break;
			}
		}
		return result;
	}

	public E getEntry(Date date) {
		return getEntry(Q3DateUtil.dateToKey(date));
	}

	public int size() {
		return profile().size();
	}

	public E first() {
		return profile().getFirst();
	}

	public E last() {
		return profile().getLast();
	}

	abstract protected LinkedList<E> profile();

	public void clear() {
		for (E entry : profile()) {
			entry.clear();
		}

	}

	public Long getKeyId() {
		return keyId;
	}
}